home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 January / Disc 1 / PCU0103CD1.iso / entertn / demos / files / aomtrial.exe / AOM / AI / SCN20P2.XS < prev    next >
Encoding:
Text File  |  2002-09-24  |  30.3 KB  |  948 lines

  1. //==============================================================================
  2. // Scn20p2: AI Scenario Script for scenario 20 player 2
  3. //==============================================================================
  4. /*
  5.    AI owner:  Mike Kidd
  6.    Scenario owner: Jeff Brown
  7.  
  8.    Overview:
  9.    The player starts on the main continent, with a TC that converts to player 1.
  10.    The CP is on a fortified island, and the player's goal is to capture the
  11.    piece of Osiris that is on the island.
  12.  
  13.    The CP starts as Set (Vision) in the second age with Anubis (plague of serpents)
  14.    as the minor god.  
  15.  
  16.    The CP will choose Nephthys (ancestors, leviathan, scorpion man) for age 3, 
  17.    and Thoth (meteor, phoenix, sea turtle) for age 4.
  18.   
  19.    The CP starts with some leviathans and sea turtles, and will use the leviathans
  20.    to transport raiding parties ashore.  The sea turtles and any trained naval
  21.    units will patrol the shoreline, with occasional incursions into the HP's bay.
  22.  
  23.    8/19/2002 Added a token economy.  Fishing plans not working.
  24.  
  25.    9/23/2002  Reduced navy size from 17 to 13 on hard.  Lowered defend 
  26.    army size by 15% on hard.
  27.  
  28.    9/24/2002  Reduced navy size on easy from 6 to 4, and on moderate from 10 to 7.
  29.    
  30.      
  31. */
  32. //==============================================================================
  33.  
  34.  
  35. include "scn lib.xs";
  36.  
  37.  
  38. // *****************************************************************************
  39. //
  40. // Globals
  41. //
  42. // *****************************************************************************
  43.  
  44. // Attack routes and queries
  45.  
  46.  
  47.  
  48. // Army control
  49. int   lastAttackPlan = -1;       // Used to find "my army" for god power position info
  50. int   defendPlan = -1;
  51. int   navalDefendPlan = -1;
  52. bool  defendOnly = false;        // When true, cancels last attack plan, all military go to defense
  53. int   explorePlan = -1;            // The naval explore plan
  54.  
  55.                                  // The following are set in main() based on difficulty level.
  56. int      nextAttackTime = 240000;   // Will be adjusted for the wakeup time
  57. int      attackInterval = 240000;   // Attack every 4:00
  58. float    attackSize = 6.0;
  59. float    attackMultiplier = 1.2;
  60. int      maxAttackSize = 10;
  61. float    totalArmySize = 25; 
  62. float    totalNavySize = 8; 
  63. float    standardDelay = 30;      
  64.  
  65.  
  66. int   maintainID1 = -1;          // Maintain plan for primary military unit
  67. int   maintainQty1 = 3;         // Quantity to maintain
  68. int   maintainUnit1 = cUnitTypeSpearman;        // Unit type
  69. int   maintainDelay1 = 30;       // Interval between training units
  70.  
  71. int   maintainID2 = -1;          // Maintain plan for secondary military unit
  72. int   maintainQty2 = 3;         // Quantity to maintain
  73. int   maintainUnit2 = cUnitTypeAnubite;        // Unit type
  74. int   maintainDelay2 = 60;       // Interval between training units
  75.  
  76.  
  77. int   maintainID3 = -1;          // Maintain plan for tertiary military unit
  78. int   maintainQty3 = 3;         // Quantity to maintain
  79. int   maintainUnit3 = cUnitTypeKebenit;        // Unit type
  80. int   maintainDelay3 = 30;       // Interval between training units
  81.  
  82.  
  83. int   maintainID4 = -1;          // Maintain plan for quatenary military unit
  84. int   maintainQty4 = 2;         // Quantity to maintain
  85. int   maintainUnit4 = cUnitTypeSeaTurtle;        // Unit type
  86. int   maintainDelay4 = 60;       // Interval between training units
  87.  
  88.  
  89. int   maintainIDScout = -1;      // Scout unit
  90. int   maintainQtyScout = -1;
  91. int   maintainUnitScout = -1;
  92. int   maintainDelayScout = -1;
  93.  
  94.  
  95.  
  96.  
  97. // Cinematic blocks
  98. const string cbTownCenter = "1422";
  99. const string cbNavyPatrol1 = "1423";
  100. const string cbNavyPatrol2 = "1424";
  101. const string cbNavyPatrol3 = "1425";
  102. const string cbNavyPatrol4 = "1426";
  103. const string cbNavyPatrol5 = "1427";
  104. const string cbBay = "1428";
  105. const string cbDefendEast = "1435";
  106. const string cbDefendWest = "1436";
  107. const string cbMainland = "2028";
  108. const string cbBeachWest = "2821";
  109.  
  110.  
  111.  
  112. // Misc.
  113. int   age2Time = 420000;    // 7 min....will be adjusted in main() for difficulty
  114. int   age3Time = 960000;   // 16 min
  115. int   age4Time = 1620000;  // 27 min
  116. int   startTime = -1;      // Time of the wakeup() function...will be added to the age times.
  117.  
  118. // Econ
  119. int   maxVills = 20;        // Will scale with difficulty
  120. int   maxFishBoats = 10;    // Including one to scout
  121. float goldPercent = 0.25;
  122. float woodPercent = 0.25;
  123. float foodPercent = 0.5;
  124. int   gathererTypeID = -1;
  125. int   fishGatherer = -1;
  126. int   mainBase = -1;
  127. float mainRadius = 100.0;
  128. const string cbCenter = "1422";
  129.  
  130.  
  131.  
  132. // *****************************************************************************
  133. //
  134. //                                FUNCTIONS
  135. //
  136. // *****************************************************************************
  137.  
  138.  
  139. // Called by trigger when the cinematics are done
  140. void wakeup(int parm=-1)
  141. {
  142.    static bool alreadyRun = false;
  143.    aiEcho("Wakeup running at "+timeString()+".");
  144.    if (alreadyRun == true)
  145.       return;
  146.    alreadyRun = true;
  147.  
  148.    startTime = xsGetTime();
  149.    age2Time = age2Time + startTime;
  150.    xsEnableRule("goToAge3");
  151.    age3Time = age3Time + startTime;    // Adjust for delay in wakeup. 
  152.    age4Time = age4Time + startTime;
  153.    nextAttackTime = nextAttackTime + startTime;
  154.  
  155.    xsEnableRule("useTornado");
  156.    xsEnableRule("useAncestors");
  157.    xsEnableRule("useRain");
  158.  
  159.    // Init maintain plans
  160.    if (maintainUnit1 > 0)
  161.       maintainID1 = maintainUnit(maintainUnit1, maintainQty1, cInvalidVector, maintainDelay1);
  162.    if (maintainUnit2 > 0)
  163.       maintainID2 = maintainUnit(maintainUnit2, maintainQty2, cInvalidVector, maintainDelay2); 
  164.    if (maintainUnit3 > 0)
  165.       maintainID3 = maintainUnit(maintainUnit3, maintainQty3, cInvalidVector, maintainDelay3);  
  166.    if (maintainUnit4 > 0)
  167.       maintainID4 = maintainUnit(maintainUnit4, maintainQty4, cInvalidVector, maintainDelay4);  
  168.    if (maintainUnitScout > 0)
  169.       maintainIDScout = maintainUnit(maintainUnitScout, maintainQtyScout, cInvalidVector, maintainDelayScout);
  170.  
  171.    maintainUnit(cUnitTypeLeviathan, 3, cInvalidVector, 1);  // Keep a reserve of transports
  172.  
  173.    createSimpleMaintainPlan(gathererTypeID, maxVills, true, mainBase);
  174.  
  175.    // Init low-priority defend plan to manage all extra mil units
  176.    defendPlan =aiPlanCreate("Defend Plan", cPlanDefend);
  177.    if (defendPlan >= 0)
  178.    {
  179. //      vector pointA=gTownLocation;
  180. //      pointA=xsVectorSetX(pointA, xsVectorGetX(gTownLocation)-50.0);
  181. //      vector pointB=gTownLocation;
  182. //      pointB=xsVectorSetZ(pointB, xsVectorGetZ(gTownLocation)-50.0);
  183.  
  184.       aiPlanAddUnitType(defendPlan, cUnitTypeLogicalTypeLandMilitary, 0, 200, 200);
  185. //      aiPlanAddUnitType(defendPlan, cUnitTypeSpearman, 0, 200, 200);    // All unassigned mil units, will be overridden (below) for navy
  186. //      aiPlanAddUnitType(defendPlan, cUnitTypeAnubite, 0, 200, 200);
  187. //      aiPlanAddUnitType(defendPlan, cUnitTypeChariotArcher, 0, 200, 200);
  188.       aiPlanSetDesiredPriority(defendPlan, 10);                       // Way low, below scouting and attack
  189.       aiPlanSetVariableVector(defendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbTownCenter));
  190.       aiPlanSetVariableInt(defendPlan, cDefendPlanGatherDistance, 0, 15);
  191.  
  192.       aiPlanSetVariableInt(defendPlan, cDefendPlanRefreshFrequency, 0, 5);
  193.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanAttackTypeID, 2, true);
  194.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  195.       aiPlanSetVariableInt(defendPlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  196.  
  197.       // Start with a simple 3-point patrol
  198.       aiPlanSetNumberVariableValues(defendPlan, cDefendPlanPatrolWaypoint, 3, true);
  199.       aiPlanSetVariableVector(defendPlan, cDefendPlanPatrolWaypoint, 0, kbGetBlockPosition(cbDefendEast));
  200.       aiPlanSetVariableVector(defendPlan, cDefendPlanPatrolWaypoint, 1, kbGetBlockPosition(cbTownCenter));
  201.       aiPlanSetVariableVector(defendPlan, cDefendPlanPatrolWaypoint, 2, kbGetBlockPosition(cbDefendWest));
  202.       aiPlanSetVariableBool(defendPlan, cDefendPlanPatrol, 0, true);
  203.  
  204.       aiPlanSetVariableFloat(defendPlan, cDefendPlanEngageRange, 0, 40);
  205.  
  206.       aiPlanSetActive(defendPlan);
  207.    }
  208.  
  209.  
  210.    // Init moderate-priority defend plan to manage all naval mil units
  211.    navalDefendPlan =aiPlanCreate("Naval Defend Plan", cPlanDefend);
  212.    if (navalDefendPlan >= 0)
  213.    {
  214. //      vector pointA=gTownLocation;
  215. //      pointA=xsVectorSetX(pointA, xsVectorGetX(gTownLocation)-50.0);
  216. //      vector pointB=gTownLocation;
  217. //      pointB=xsVectorSetZ(pointB, xsVectorGetZ(gTownLocation)-50.0);
  218.  
  219. //      aiPlanAddUnitType(navalDefendPlan, cUnitTypeLogicalTypeNavalMilitary, 0, 200, 200);
  220.       aiPlanAddUnitType(navalDefendPlan, cUnitTypeKebenit, 0, 200, 200);    // All navy except transports
  221.       aiPlanAddUnitType(navalDefendPlan, cUnitTypeSeaTurtle, 0, 200, 200);
  222. //      aiPlanAddUnitType(navalDefendPlan, cUnitTypeLeviathan, 0,200, 200); // What the heck, try the levi's, too.
  223.       aiPlanSetDesiredPriority(navalDefendPlan, 60);                       // Somewhat low, but above land attack plan 
  224.       aiPlanSetVariableVector(navalDefendPlan, cDefendPlanDefendPoint, 0, kbGetBlockPosition(cbTownCenter));
  225.  
  226.       aiPlanSetVariableInt(navalDefendPlan, cDefendPlanRefreshFrequency, 0, 5);
  227.       aiPlanSetNumberVariableValues(navalDefendPlan, cDefendPlanAttackTypeID, 2, true);
  228.       aiPlanSetVariableInt(navalDefendPlan, cDefendPlanAttackTypeID, 0, cUnitTypeUnit);
  229.       aiPlanSetVariableInt(navalDefendPlan, cDefendPlanAttackTypeID, 1, cUnitTypeBuilding);
  230.  
  231.       aiPlanSetVariableInt(navalDefendPlan, cDefendPlanGatherDistance, 0, 20);
  232.  
  233.       // Start with a simple 3-point patrol
  234.       aiPlanSetNumberVariableValues(navalDefendPlan, cDefendPlanPatrolWaypoint, 5, true);
  235.       aiPlanSetVariableVector(navalDefendPlan, cDefendPlanPatrolWaypoint, 0, kbGetBlockPosition(cbNavyPatrol1));
  236.       aiPlanSetVariableVector(navalDefendPlan, cDefendPlanPatrolWaypoint, 1, kbGetBlockPosition(cbNavyPatrol2));
  237.       aiPlanSetVariableVector(navalDefendPlan, cDefendPlanPatrolWaypoint, 2, kbGetBlockPosition(cbNavyPatrol3));
  238.       aiPlanSetVariableVector(navalDefendPlan, cDefendPlanPatrolWaypoint, 3, kbGetBlockPosition(cbNavyPatrol4));
  239.       aiPlanSetVariableVector(navalDefendPlan, cDefendPlanPatrolWaypoint, 4, kbGetBlockPosition(cbNavyPatrol5));
  240.       aiPlanSetVariableBool(navalDefendPlan, cDefendPlanPatrol, 0, true);
  241.  
  242.       aiPlanSetVariableFloat(navalDefendPlan, cDefendPlanEngageRange, 0, 40);
  243.  
  244.       aiPlanSetActive(navalDefendPlan);
  245.    }
  246.  
  247. //   xsEnableRule("useSpy");
  248.    xsEnableRule("scout");
  249.    xsEnableRule("attackGenerator");
  250.    xsEnableRule("fishing");
  251. }
  252.  
  253. void initMainBase()
  254. {
  255.    // Nuke bases, add one base to rule them all
  256.    kbBaseDestroyAll(cMyID);
  257.  
  258.    mainBase = kbBaseCreate(cMyID, "Base "+kbBaseGetNextID(), kbGetBlockPosition(cbCenter), mainRadius);
  259.    if (mainBase < 0)
  260.       aiEcho("***** Main base creation failed. *****");
  261.  
  262.    vector baseFront=xsVectorNormalize(kbGetMapCenter()-kbGetBlockPosition(cbCenter));     // Set front
  263.    kbBaseSetFrontVector(cMyID, mainBase, baseFront);                 
  264.    kbBaseSetMaximumResourceDistance(cMyID, mainBase, mainRadius+50.0);                    // Gather up to 50m beyond base perimeter
  265.    kbBaseSetMain(cMyID, mainBase, true);     // Make this the main base
  266.  
  267.    // Add the buildings
  268.    int buildingQuery = -1;
  269.    int count = 0;
  270.    buildingQuery = kbUnitQueryCreate("Building Query");     // All buildings in the base
  271.    configQuery(buildingQuery, cUnitTypeBuilding, -1, cUnitStateAliveOrBuilding, cMyID, kbGetBlockPosition(cbCenter), false, mainRadius);
  272.    kbUnitQueryResetResults(buildingQuery);
  273.    count = kbUnitQueryExecute(buildingQuery);
  274.  
  275.    int i = 0;
  276.    int buildingID = -1;
  277.    for (i=0; < count)
  278.    {
  279.       buildingID = kbUnitQueryGetResult(buildingQuery, i);
  280.       // Add it to the base
  281.       kbBaseAddUnit( cMyID, mainBase, buildingID );
  282.    }
  283. }
  284.  
  285.  
  286. void initEcon()
  287. {
  288.     //-- get our fish gatherer.
  289.     fishGatherer = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionFish,0);
  290.    gathererTypeID = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionGatherer,0);
  291.  
  292.    aiSetAutoGatherEscrowID(cRootEscrowID);
  293.    aiSetAutoFarmEscrowID(cRootEscrowID);
  294.    
  295.    int herdPlanID=aiPlanCreate("GatherHerdable Plan", cPlanHerd);
  296.    if (herdPlanID >= 0)
  297.    {
  298.       aiPlanAddUnitType(herdPlanID, cUnitTypeHerdable, 0, 100, 100);
  299.       aiPlanSetVariableInt(herdPlanID, cHerdPlanBuildingTypeID, 0, cUnitTypeSettlementLevel1);
  300.       aiPlanSetActive(herdPlanID);
  301.    }
  302.  
  303.    aiSetResourceGathererPercentageWeight(cRGPScript, 1);
  304.    aiSetResourceGathererPercentageWeight(cRGPCost, 0);
  305.  
  306.    kbSetAICostWeight(cResourceFood, 1.0);
  307.    kbSetAICostWeight(cResourceWood, 0.7);
  308.    kbSetAICostWeight(cResourceGold, 0.8);
  309.    kbSetAICostWeight(cResourceFavor, 7.0);
  310.  
  311.    aiSetResourceGathererPercentage(cResourceFood, foodPercent, false, cRGPScript);
  312.    aiSetResourceGathererPercentage(cResourceWood, woodPercent, false, cRGPScript);
  313.    aiSetResourceGathererPercentage(cResourceGold, goldPercent, false, cRGPScript);
  314.    aiSetResourceGathererPercentage(cResourceFavor, 0.0, false, cRGPScript);
  315.    aiNormalizeResourceGathererPercentages(cRGPScript);
  316.  
  317.    //bool aiSetResourceBreakdown( int resourceTypeID, int resourceSubTypeID, int numberPlans, int planPriority, float percentage, int baseID )
  318. //    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeEasy, numFoodEasyPlans, 50, 1.0, gMainBaseID);
  319. //   aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeHuntAggressive, numFoodHuntAggressivePlans, 100, 1.0, gMainBaseID);
  320.    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFish, 1, 50, 1.0, mainBase);
  321.    aiSetResourceBreakdown(cResourceFood, cAIResourceSubTypeFarm, 1, 50, 1.0, mainBase);
  322.    aiSetResourceBreakdown(cResourceWood, cAIResourceSubTypeEasy, 1, 50, 1.0, mainBase);
  323.     aiSetResourceBreakdown(cResourceGold, cAIResourceSubTypeEasy, 1, 50, 1.0, mainBase);
  324. //   aiSetResourceBreakdown(cResourceFavor, cAIResourceSubTypeEasy, numFavorPlans, 50, 1.0, gMainBaseID);
  325. }
  326.  
  327.  
  328.  
  329.  
  330.  
  331. // Called via trigger, cancel last offensive plan and put all units on defense.
  332. void defend(int parm=-1)
  333. {
  334.    aiEcho("Defend function called.");
  335.    defendOnly = true;
  336.    aiPlanDestroy(lastAttackPlan);
  337. }
  338.  
  339.  
  340.  
  341.  
  342. // Used to delete units that are being replaced by a new type.
  343. void deleteObsoleteUnits(int unitType=cUnitTypeUnit, int player=2, vector center=vector(-1,-1,-1), float radius = 20.0, float percent=1.00)
  344. {
  345.    // Make query
  346.    int query = -1;
  347.    int count = -1;
  348.  
  349.    query = kbUnitQueryCreate("Unit deletion query");
  350.    if ( configQuery(query, unitType, -1, cUnitStateAlive, player, center, false, radius) == false)
  351.       return;
  352.    kbUnitQueryResetResults(query);
  353.    count = kbUnitQueryExecute(query);
  354.    
  355.    // Iterate list, deleting percentage indicated
  356.    float remainder=0.0; // Used to handle percentages, when this gets >= 1, it's time to delete a unit.
  357.    
  358.    for (i=0; <count)
  359.    {
  360.       remainder = remainder + percent;
  361.       if (remainder >= 1.0)   // time to delete one
  362.       {
  363.          aiTaskUnitDelete(kbUnitQueryGetResult(query,i));
  364.          remainder = remainder - 1.0;
  365.       }
  366.    }
  367. }
  368.  
  369.  
  370. void age2EventHandler(int bogus=-1)
  371. {
  372.    xsEnableRule("goToAge3");
  373.    xsEnableRule("getAge2UnitUpgrades");
  374.    xsEnableRule("getAge2ArmoryUpgrades");
  375.  
  376.  
  377.  
  378. //   xsEnableRule("useUndermine");
  379.  
  380. }
  381.  
  382.  
  383.  
  384. void age3EventHandler(int bogus=-1)
  385. {
  386.  
  387.    if (age4Time > 0) // May be suppressed for difficulty
  388.       xsEnableRule("goToAge4");
  389.    xsEnableRule("getAge3UnitUpgrades");
  390.    xsEnableRule("getAge3ArmoryUpgrades");
  391.  
  392.  
  393. // aiPlanSetVariableInt(navyMaintainID, cTrainPlanUnitType, 0, navyUnit);
  394. //   if (navyUnit != oldUnit)
  395. //   {
  396. //      deleteObsoleteUnits(oldUnit, 2, kbGetBlockPosition(cbFinalGate), 50, .5);   // Delete half of the old units
  397. //      aiEcho("Deleting units: "+kbGetProtoUnitName(oldUnit));
  398. //   }
  399.  
  400. //   xsEnableRule("useFlamingWeapons");
  401. }
  402.  
  403.  
  404.  
  405. void age4EventHandler(int bogus=-1)
  406. {
  407.    xsEnableRule("getAge4UnitUpgrades");
  408.    xsEnableRule("getAge4ArmoryUpgrades");
  409.  
  410.  
  411.  
  412.  
  413.   //xsEnableRule("useNidhogg");
  414. }
  415.  
  416.  
  417.  
  418.  
  419. void attack(int size=0)
  420. {
  421.    if (defendOnly == true)
  422.       return;
  423.  
  424.    int   attackID=aiPlanCreate("Attack at "+timeString(true)+" ", cPlanAttack);
  425.    if (attackID < 0)
  426.       return;
  427.  
  428.    if (aiPlanSetVariableInt(attackID, cAttackPlanPlayerID, 0, 1) == false)
  429.       return;
  430.  
  431.    if (aiPlanSetNumberVariableValues(attackID, cAttackPlanTargetTypeID, 3, true) == false)
  432.       return;
  433.  
  434.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 0, cUnitTypeUnit);
  435.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 1, cUnitTypeBuilding);
  436.    aiPlanSetVariableInt(attackID, cAttackPlanTargetTypeID, 2, cUnitTypeAbstractWall);
  437.  
  438.    // Specify other continent so that armies will transport
  439.    aiPlanSetNumberVariableValues( attackID, cAttackPlanTargetAreaGroups,  1, true);  
  440.    aiEcho("Area group for mainland is "+kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbMainland)));
  441.    aiPlanSetVariableInt(attackID, cAttackPlanTargetAreaGroups, 0, kbAreaGroupGetIDByPosition(kbGetBlockPosition(cbMainland)));
  442.    
  443.    aiPlanSetVariableVector(attackID, cAttackPlanGatherPoint, 0, kbGetBlockPosition(cbTownCenter));
  444.    aiPlanSetVariableFloat(attackID, cAttackPlanGatherDistance, 0, 20.0);
  445.  
  446.    switch(kbGetAge())      // Set the targets and unit composition
  447.    {
  448.    case cAge1:
  449.       {  
  450.          aiPlanAddUnitType(attackID, cUnitTypeLogicalTypeLandMilitary, 1, size, size);
  451.          break;
  452.       }
  453.    case cAge2:
  454.       {  
  455.          aiPlanAddUnitType(attackID, cUnitTypeLogicalTypeLandMilitary, 1, size, size);
  456.          break;
  457.       }
  458.    case cAge3:
  459.       {   
  460.          aiPlanAddUnitType(attackID, cUnitTypeSpearman, 1, (4*size)/5, (4*size)/5);
  461.          aiPlanAddUnitType(attackID, cUnitTypeMythUnit, 1, 1+size/5, 1+size/5);
  462.          break;
  463.       }
  464.    case cAge4:
  465.       {  
  466.          aiPlanAddUnitType(attackID, cUnitTypeSpearman, 1, (4*size)/5, (4*size)/5);
  467.          aiPlanAddUnitType(attackID, cUnitTypeMythUnit, 1, 1+size/5, 1+size/5);
  468.          break;
  469.       }
  470.    }
  471.  
  472.    aiPlanSetInitialPosition(attackID, kbGetBlockPosition(cbTownCenter));
  473.    aiPlanSetRequiresAllNeedUnits(attackID, false);
  474.    aiPlanSetDesiredPriority(attackID, 50);   // Less than scouting, more than defense
  475.    aiPlanSetActive(attackID);
  476.    aiEcho("Activating attack plan "+attackID+" with appx "+size+" units.");
  477.    lastAttackPlan = attackID; // update the global var
  478. }
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485. void main()
  486. {
  487.    aiEcho("Starting Scn20p2.xs");
  488.  
  489.    //Calculate some areas.
  490.    kbAreaCalculate(1200.0);
  491.    aiRandSetSeed();
  492.    kbSetTownLocation(kbGetBlockPosition(cbTownCenter));
  493.    aiSetAttackResponseDistance(20.0);
  494.  
  495.    aiSetAgeEventHandler(cAge2, "age2EventHandler");
  496.    aiSetAgeEventHandler(cAge3, "age3EventHandler");
  497.    aiSetAgeEventHandler(cAge4, "age4EventHandler");
  498.  
  499.    kbEscrowSetPercentage( cEconomyEscrowID, cAllResources, 0.0);
  500.    kbEscrowSetPercentage( cMilitaryEscrowID, cAllResources, 0.0);
  501.    kbEscrowAllocateCurrentResources();
  502.  
  503.    aiEcho("Difficulty = "+aiGetWorldDifficulty());   
  504.  
  505.    switch(aiGetWorldDifficulty())      // Set up the attack control and age-up parameters
  506.    {
  507.    case 0:     // Easy
  508.       {
  509.          nextAttackTime = 300000;   // 5 min
  510.          attackInterval = 240000;   // 4 min
  511.          attackSize = 2.0;          
  512.          attackMultiplier = 1.1;    // 10% per 4 min
  513.          maxAttackSize = 7;
  514.          totalArmySize = 10;
  515.          totalNavySize = 4;
  516.          standardDelay = 90;
  517.          age2Time = 900000;   // 15 min
  518.          age3Time = 1800000;  // 30 min
  519.          age4Time = -1;       // Not permitted
  520.          break;
  521.       }
  522.    case 1:     // Moderate
  523.       {
  524.          nextAttackTime = 240000;
  525.          attackInterval = 240000;
  526.          attackSize = 3.0;
  527.          attackMultiplier = 1.2;    // 20% per 4 min
  528.          maxAttackSize = 15;
  529.          totalArmySize = 20;
  530.          totalNavySize = 7;
  531.          standardDelay = 60;
  532.          age2Time = 600000;   // 10 min
  533.          age3Time = 900000;  // 15 min
  534.          age4Time = 1800000;  // 30 min
  535.          break;
  536.       }
  537.    case 2:     // Difficult
  538.       {
  539.          nextAttackTime = 120000;
  540.          attackInterval = 138000;
  541.          attackSize = 5.0;
  542.          attackMultiplier = 1.3;    // 30% per 3 min
  543.          maxAttackSize = 30;
  544.          totalArmySize = 34;
  545.          totalNavySize = 13;
  546.          standardDelay = 30;
  547.          age2Time = 420000;  // 7 min
  548.          age3Time = 600000;  // 10 min
  549.          age4Time = 1200000; // 20 min
  550.          break;
  551.       }
  552.    case 3:     // Nightmare
  553.       {
  554.          nextAttackTime = 60000;
  555.          attackInterval = 120000;
  556.          attackSize = 6.0;
  557.          attackMultiplier = 1.3;    // 30% per 2 min
  558.          maxAttackSize = 45;
  559.          totalArmySize = 60;
  560.          totalNavySize = 25;
  561.          standardDelay = 20;
  562.          age2Time = 240000;  // 4 min
  563.          age3Time = 300000;  // 5 min
  564.          age4Time = 600000;  // 10 min
  565.          break;
  566.       }
  567.    }
  568.  
  569.    maintainDelay1 = standardDelay/3;       // Interval between training units
  570.    maintainQty1 = totalArmySize/2;
  571.    maintainDelay2 = standardDelay;       
  572.    maintainQty2 = 1 + (totalArmySize/6);
  573.    maintainDelay3 = standardDelay;      
  574.    maintainQty3 = 2*(totalNavySize/3);
  575.    maintainDelay4 = 4*standardDelay;      
  576.    maintainQty4 = 1 + (totalNavySize/3);
  577.    maintainUnit(cUnitTypeChariotArcher, (totalArmySize/3), cInvalidVector, (standardDelay/2));
  578.  
  579.  
  580.    initMainBase();
  581.    initEcon();
  582. }
  583.  
  584.  
  585.  
  586.  
  587.  
  588.  
  589.  
  590. // *****************************************************************************
  591. //
  592. // RULES
  593. //
  594. // *****************************************************************************
  595.  
  596. rule scout
  597.    inactive
  598.    minInterval 5
  599. {
  600.    // just set up an explore plan
  601.    explorePlan = aiPlanCreate("Explore", cPlanExplore);
  602.    if(explorePlan >= 0)
  603.    {
  604.       aiPlanSetVariableFloat( explorePlan, cExplorePlanLOSMultiplier,  0, 4.0 );
  605.       aiPlanAddUnitType(explorePlan, cUnitTypeKebenit, 1, 1, 1);
  606.       aiPlanSetDesiredPriority(explorePlan, 90);
  607.       aiPlanSetActive(explorePlan);
  608.    }
  609.    xsDisableSelf();
  610. }
  611.  
  612.  
  613. rule fishing
  614.    minInterval 30
  615.    inactive
  616. {
  617.     //-- get our fish gatherer.
  618.     fishGatherer = kbTechTreeGetUnitIDTypeByFunctionIndex(cUnitFunctionFish,0);
  619.  
  620.    if (maxFishBoats > 0)
  621.       createSimpleMaintainPlan(fishGatherer, maxFishBoats, true, mainBase);
  622.  
  623.    if (maxFishBoats < 2)
  624.    {
  625.       // At most, just a scout
  626.       xsDisableSelf();
  627.       return;
  628.    }
  629.     //-- Get the closest water area.  if there isn't one, we can't fish.
  630.     static int areaID = -1;
  631.     if(areaID == -1)
  632.         areaID = kbAreaGetClosetArea(kbGetBlockPosition(cbCenter), cAreaTypeWater);
  633.  
  634. //    if( kbSetupForResource(mainBase, cResourceWood, 25.0, 600) == false)
  635. //      return;
  636.    
  637.  
  638.     //-- Create the fish plan.
  639.     int fishPlanID=aiPlanCreate("FishPlan", cPlanFish);
  640.     if (fishPlanID >= 0)
  641.     {
  642.         aiEcho("Starting up the fishing plan.  Will fish when I find fish.");
  643.       aiPlanSetDesiredPriority(fishPlanID, 70);
  644.         aiPlanSetVariableVector(fishPlanID, cFishPlanLandPoint, 0, kbGetBlockPosition(cbCenter));
  645.         //-- If you don't explicitly set the water point, the plan will find one for you.
  646.         aiPlanSetVariableBool(fishPlanID, cFishPlanAutoTrainBoats, 0, false);   // I'm going to have a  maintain plan for fishing + scouting combined
  647.         aiPlanSetEscrowID(fishPlanID, cRootEscrowID);
  648.       aiPlanSetVariableFloat(fishPlanID, cFishPlanMaximumDockDist, 0, 500.0);
  649.         aiPlanAddUnitType(fishPlanID, fishGatherer, 1, maxFishBoats-1, maxFishBoats-1);
  650.         aiPlanSetActive(fishPlanID);
  651.     }
  652.  
  653.  
  654.  
  655. /*
  656.    // Add a fish boat explore plan
  657.    int exploreWaterID = aiPlanCreate("Water Explore", cPlanExplore);
  658.    if(exploreWaterID >= 0)
  659.    {
  660.       //aiPlanAddVariableFloat( exploreID, cExplorePlanLOSMultiplier, "LOS Multiplier", 1);
  661.       aiPlanSetVariableFloat( exploreWaterID, cExplorePlanLOSMultiplier,  0, 4.0 );
  662.       aiPlanAddUnitType(exploreWaterID, fishGatherer, 1, 1, 1);
  663.       aiPlanSetDesiredPriority(exploreWaterID, 90);
  664.       aiPlanSetActive(exploreWaterID);
  665.    }
  666. */
  667.  
  668.     xsDisableSelf();
  669. }
  670.  
  671.  
  672.  
  673.  
  674.  
  675.  
  676. rule goToAge2
  677.    inactive
  678.    minInterval 10
  679. {
  680.    if ( xsGetTime() < age2Time)
  681.       return;
  682.    researchTech(cTechAge2Heimdall);
  683.    xsDisableSelf();
  684. }
  685.  
  686.  
  687.  
  688. rule goToAge3
  689.    inactive
  690.    mininterval 20
  691. {
  692.    if ( xsGetTime() < age3Time )
  693.       return;
  694.    researchTech(cTechAge3Nephthys);
  695.    xsDisableSelf();
  696. }
  697.  
  698.  
  699. rule goToAge4
  700.    inactive
  701.    mininterval 20
  702. {
  703.    if ( xsGetTime() < age4Time )
  704.       return;
  705.    researchTech(cTechAge4Thoth);
  706.    xsDisableSelf();
  707. }
  708.  
  709.  
  710.  
  711. rule getAge2UnitUpgrades
  712.    inactive
  713.    minInterval 20
  714. {
  715.    if ( xsGetTime() < (age2Time + age2Time + age3Time)/3 )
  716.       return;     // Wait till 1/3 to age3
  717.    researchTech(cTechMediumInfantry);
  718.    researchTech(cTechMediumCavalry);
  719.    xsDisableSelf();
  720. }
  721.  
  722. rule getAge2ArmoryUpgrades
  723.    inactive
  724. {
  725.    if ( xsGetTime() < (age2Time + age3Time + age3Time)/3 )
  726.       return;     // Wait till 2/3 to age3
  727.    aiEcho("Getting age 2 armory upgrades");
  728.    researchTech(cTechCopperWeapons);
  729.    researchTech(cTechCopperMail);
  730.    researchTech(cTechCopperShields);
  731.    xsDisableSelf();
  732. }
  733.  
  734. rule getAge3UnitUpgrades
  735.    inactive
  736. {
  737.    if ( xsGetTime() < (age3Time+180000) )
  738.       return;
  739.    researchTech(cTechHeavyInfantry);
  740.    researchTech(cTechHeavyCavalry);
  741.    xsDisableSelf();
  742. }
  743.  
  744. rule getAge3ArmoryUpgrades
  745.    inactive
  746. {
  747.    if ( xsGetTime() < (age3Time+300000) )
  748.       return;
  749.    researchTech(cTechBronzeWeapons);
  750.    researchTech(cTechBronzeMail);
  751.    researchTech(cTechBronzeShields);
  752.    xsDisableSelf();
  753. }
  754.  
  755. rule getAge4UnitUpgrades
  756.    inactive
  757. {
  758.    if ( xsGetTime() < (age4Time+300000) )
  759.       return;
  760.    researchTech(cTechChampionInfantry);
  761.    researchTech(cTechChampionCavalry);
  762.    xsDisableSelf();
  763. }
  764.  
  765. rule getAge4ArmoryUpgrades
  766.    inactive
  767. {
  768.    if ( xsGetTime() < (age4Time+600000) )
  769.       return;
  770.    researchTech(cTechIronWeapons);
  771.    researchTech(cTechIronMail);
  772.    researchTech(cTechIronShields);
  773.    xsDisableSelf();
  774. }
  775.  
  776. rule favorGenerator
  777.    active
  778. {
  779.    aiResourceCheat( 2, cResourceFavor, 100.0 );    // Max out the favor every 15 seconds
  780.    kbEscrowAllocateCurrentResources();             // Make sure the escrow knows about it.
  781. }
  782.  
  783.  
  784. rule attackGenerator
  785.    minInterval 10
  786.    inactive
  787. {
  788.    //aiEcho("attack check running, next time is "+nextAttackTime);
  789.    if ( xsGetTime() < nextAttackTime )
  790.       return;
  791.  
  792.    attack(attackSize);
  793.    nextAttackTime = xsGetTime() + attackInterval;
  794.    attackSize = attackSize * attackMultiplier;
  795.    if (attackSize > maxAttackSize)
  796.       attackSize = maxAttackSize;
  797.    aiEcho("Next attack size will be "+attackSize+".");
  798. }
  799.  
  800.  
  801. rule useTornado // Drop a tornado if we see enemy navy/fishing units near my water scout, unless its near the bay.
  802.    minInterval 5
  803.    inactive
  804. {
  805.    // look for a group of 4 enemy units at my water scout's location
  806.    int targetUnit = -1;
  807.    int fishBoatCount = -1;
  808.    int enemyCount = -1;
  809.  
  810.    vector pVec = aiPlanGetLocation(explorePlan);
  811.    if (xsVectorGetX(pVec)<0)
  812.       return;
  813.  
  814.    static int tempQuery = -1;
  815.    if (tempQuery < 0)
  816.    {  // Doesn't exist, set it up
  817.       tempQuery = kbUnitQueryCreate("useTornado");
  818.  
  819.       if ( configQuery(tempQuery, cUnitTypeUtilityShip, -1, cUnitStateAlive, 1, pVec, true, 50) == false)
  820.          return;
  821.    }
  822.    else
  823.    {
  824.       kbUnitQuerySetUnitType(tempQuery, cUnitTypeUtilityShip);
  825.       kbUnitQuerySetPosition(tempQuery, pVec);
  826.    }
  827.  
  828.    kbUnitQueryResetResults(tempQuery);
  829.    fishBoatCount = kbUnitQueryExecute(tempQuery);  
  830.  
  831.    kbUnitQuerySetUnitType(tempQuery, cUnitTypeLogicalTypeNavalMilitary);
  832.    enemyCount = kbUnitQueryExecute(tempQuery);     // Add military units to fish boat list
  833.    if (enemyCount < 4)
  834.       return;
  835.  
  836.    aiEcho("Tornado:  Fish boats = "+fishBoatCount+", Total units = "+enemyCount);
  837.    targetUnit = kbUnitQueryGetResult(tempQuery, enemyCount/2);  // grab middle unit
  838.  
  839.    // confirm LOS
  840.  
  841.    if ( kbUnitVisible(targetUnit) != true )
  842.    {
  843.       aiEcho("Don't have LOS to unit "+targetUnit);
  844.       return;
  845.    }
  846.  
  847.    // Check proximity to the bay via cbBay marker
  848.    bool tooClose = true;      // Set it false if dx or dz > 50
  849.    vector target = cInvalidVector;
  850.    vector bay = cInvalidVector;
  851.  
  852.    target = kbUnitGetPosition(targetUnit);
  853.    bay = kbGetBlockPosition(cbBay);
  854.  
  855.    float dx = 0.0;
  856.    float dz = 0.0;
  857.  
  858.    dx = xsVectorGetX(target) - xsVectorGetX(bay);
  859.    dz = xsVectorGetZ(target) - xsVectorGetZ(bay);
  860.    aiEcho("dx = "+dx+", dz = "+dz);
  861.  
  862.    if (dx < -50.0)
  863.       tooClose = false;
  864.    if (dx > 50.0)
  865.       tooClose = false;
  866.    if (dz < -50.0)
  867.       tooClose = false;
  868.    if (dz > 50.0) 
  869.       tooClose = false;
  870.  
  871.    if (tooClose == true)
  872.    {
  873.       aiEcho("Can't use tornado, too close to the bay.");
  874.       return;
  875.    }
  876.  
  877.    aiEcho("Using Tornado");
  878.    if ( aiCastGodPowerAtPosition(cTechTornado, target) == true)
  879.       xsDisableSelf();
  880.    else
  881.       aiEcho("Tornado failed at "+target);
  882. }
  883.  
  884.  
  885.  
  886. rule useAncestors // Use ancestors if there are >= 6 naval units near the cineblock on the beach.
  887.    minInterval 5
  888.    inactive
  889. {
  890.    // look for a group of 6 enemy naval units at my water scout's location
  891.    int targetUnit = -1;
  892.  
  893.    int enemyCount = -1;
  894.  
  895.  
  896.    static int tempQuery = -1;
  897.    if (tempQuery < 0)
  898.    {  // Doesn't exist, set it up
  899.       tempQuery = kbUnitQueryCreate("useAncestors");
  900.  
  901.       if ( configQuery(tempQuery, cUnitTypeLogicalTypeNavalMilitary, -1, cUnitStateAlive, 1, kbGetBlockPosition(cbBeachWest), true, 50) == false)
  902.          return;
  903.    }
  904.  
  905.  
  906.    kbUnitQueryResetResults(tempQuery);
  907.    enemyCount = kbUnitQueryExecute(tempQuery);     // Get the count
  908.    if (enemyCount < 6)
  909.       return;
  910.  
  911.    targetUnit = kbUnitQueryGetResult(tempQuery, enemyCount/2);  // grab middle unit
  912.  
  913.    // confirm LOS
  914.  
  915.    if ( kbUnitVisible(targetUnit) != true )
  916.    {
  917.       aiEcho("Don't have LOS to unit "+targetUnit);
  918.       return;
  919.    }
  920.  
  921.  
  922.  
  923.    aiEcho("Using Ancestors");
  924.    if ( aiCastGodPowerAtPosition(cTechSkeletonPower, kbUnitGetPosition(targetUnit)) == true)
  925.       xsDisableSelf();
  926.    else
  927.       aiEcho("Ancestors failed at "+kbUnitGetPosition(targetUnit));
  928. }
  929.  
  930.  
  931.  
  932. rule useRain
  933.    minInterval 5
  934.    inactive
  935. {     // 10 minutes after wakeup()
  936.    static int rainTime = 0;
  937.  
  938.    if (rainTime == 0)
  939.       rainTime = xsGetTime()+10*60*1000;
  940.  
  941.    if (xsGetTime() < rainTime)
  942.       return;
  943.  
  944.    aiCastGodPowerAtPosition(cTechRain, kbGetBlockPosition(cbTownCenter));
  945.    xsDisableSelf();
  946. }
  947.  
  948.